package fr.afcepf.projet2.metiers.webservices.comptes;

import fr.afcepf.projet2.metiers.donnees.assembleur.comptes.AdresseAssembleur;
import fr.afcepf.projet2.metiers.donnees.assembleur.comptes.CiviliteAssembleur;
import fr.afcepf.projet2.metiers.donnees.assembleur.comptes.TypeUtilisateurAssembleur;
import fr.afcepf.projet2.metiers.donnees.assembleur.comptes.UtilisateurAssembleur;
import fr.afcepf.projet2.metiers.donnees.dao.interfaces.comptes.IDaoAdresse;
import fr.afcepf.projet2.metiers.donnees.dao.interfaces.comptes.IDaoCivilite;
import fr.afcepf.projet2.metiers.donnees.dao.interfaces.comptes.IDaoTypeUtilisateur;
import fr.afcepf.projet2.metiers.donnees.dao.interfaces.comptes.IDaoUtilisateur;
import fr.afcepf.projet2.metiers.donnees.dto.comptes.AdresseDto;
import fr.afcepf.projet2.metiers.donnees.dto.comptes.CiviliteDto;
import fr.afcepf.projet2.metiers.donnees.dto.comptes.TypeUtilisateurDto;
import fr.afcepf.projet2.metiers.donnees.dto.comptes.UtilisateurDto;
import fr.afcepf.projet2.metiers.donnees.entites.comptes.Adresse;
import fr.afcepf.projet2.metiers.donnees.entites.comptes.Utilisateur;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

/** Implémentation du WebService gérant les comptes Utilisateurs
 *
 * @author Mageta
 */
@WebService(serviceName = "WsComptes")
@Stateless()
public class WsComptes {

    @EJB
    private IDaoUtilisateur iDaoUtilisateur;
    @EJB
    private IDaoTypeUtilisateur iDaoTypeUtilisateur;
    @EJB
    private IDaoCivilite iDaoCivilite;
    @EJB
    private IDaoAdresse iDaoAdresse;

    /** Renvoie un DTO d'utilisateur à partir de son adresse e-mail
     * 
     * @param email Adresse e-mail de l'utilisateur demandé
     * @return DTO de l'utilisateur demandé
     */
    @WebMethod(operationName = "getByEmail")
//    @Override
    public UtilisateurDto getByEmail(
            @WebParam(name = "email")
            final String email) 
        throws InformationManquanteException, UtilisateurInexistantException {
        UtilisateurDto res;
        if (!email.isEmpty()) {
            Utilisateur entite = iDaoUtilisateur.obtenirParEmail(email);
            if (entite == null) {
                throw new UtilisateurInexistantException(email);
            }
            res = UtilisateurAssembleur.creationUtilisateurDto(entite);
            return res;
        } else {
            throw new InformationManquanteException("email");
        }
    }

    /** Met à jour les modifications effectuées sur un utilisateur
     * 
     * @param client utilisateur à mettre à jour
     */
    @WebMethod(operationName = "modifierClient")
    public void modifierClient(
            @WebParam(name = "client")
            final UtilisateurDto client) {
        if (client != null) {
            iDaoUtilisateur
                    .modifier(
                    UtilisateurAssembleur.updateUtilisateur(client));
            // TODO Vérifier règles métiers
        }
    }

    /** Récupère le DTO d'un utilisateur à partir de son identifiant
     * 
     * @param idClient identifiant de l'utilisateur à recherché
     * @return DTO de l'utilisateur recherché
     */
    @WebMethod(operationName = "getById")
    public UtilisateurDto getById(
            @WebParam(name = "idClient")
            final int idClient) 
            throws UtilisateurInexistantException {   
        
        Utilisateur utilisateur = iDaoUtilisateur.obtenirParIdUtilisateur(idClient);        
        UtilisateurDto u = UtilisateurAssembleur.creationUtilisateurDto(
                utilisateur);
        return u;
    }

    /** Sauvegarde un nouveau Client
     * 
     * @param client Client à enregistrer
     * @return client mis à jour après l'enregistrement
     */
    @WebMethod(operationName = "ajoutClient")
    public UtilisateurDto ajoutClient(
            @WebParam(name = "utilisateurDto")
            final UtilisateurDto utilisateurDto) 
            throws InformationManquanteException {
        if (utilisateurDto.getEmail() == null) {
            throw new InformationManquanteException("E-mail");
        }
        if (utilisateurDto.getMotDePasse() == null) {
            throw new InformationManquanteException("Mot de passe");
        }
        if (utilisateurDto.getNom() == null) {
            throw new InformationManquanteException("Nom");
        }
        if (utilisateurDto.getPrenom() == null) {
            throw new InformationManquanteException("Prénom");
        }
        String sha = cryptageMotDePasee(utilisateurDto.getMotDePasse());
        utilisateurDto.setMotDePasse(sha);
        Utilisateur utilisateur = iDaoUtilisateur.ajouter(
                UtilisateurAssembleur.updateUtilisateur(utilisateurDto));
        return UtilisateurAssembleur.creationUtilisateurDto(utilisateur);
    }

    /** Connexion d'un utilisateur
     * 
     * @param login login de l'utilisateur (adresse email)
     * @param mdp mot de passe de l'utilisateur
     * @return DTO de l'utilisateur en cas connexion réussie
     */
    @WebMethod(operationName = "connectionClient")
    public UtilisateurDto connectionClient(
            @WebParam(name = "email") final String email,
            @WebParam(name = "mdp") String mdp) 
            throws InformationManquanteException,
            MotDePasseIncorrectException, UtilisateurInexistantException {
        UtilisateurDto resultat;
        resultat = getByEmail(email); 
        if (email == null || "".equals(email)) {
            throw new InformationManquanteException("email");	
        }
        if (resultat == null) {
            throw new UtilisateurInexistantException(email);
        }
        if (mdp == null || "".equals(mdp)){
            throw new InformationManquanteException("Mot de passe");
        }
        mdp = cryptageMotDePasee(mdp);
        if (resultat != null && (resultat.getMotDePasse() == null
                || !mdp.equals(resultat.getMotDePasse()))) {
            throw new MotDePasseIncorrectException(email);
        }
        resultat.setMotDePasse("");
        return resultat;
    }

    /** Permet de récupérer la liste des Civilité
     * 
     * @return liste de toutes les civilité disponible
     */
    @WebMethod(operationName = "getAllCivilite")
    public List<CiviliteDto> getAllCivilite() {
        return CiviliteAssembleur
                .creationListeCiviliteDto(iDaoCivilite
                .rechercherParNamedQuery(
                "Civilite.findAll"));
    }

    /** Permet de récupérer la liste des type d'utilisateur
     * 
     * @return liste de type d'utilisateur
     */
    @WebMethod(operationName = "getAllTypeUtilisateur")
    public List<TypeUtilisateurDto> getAllTypeUtilisateur() 
           {
        return TypeUtilisateurAssembleur
                .creationListeTypeUtilisateurDto(iDaoTypeUtilisateur
                .rechercherParNamedQuery(
                "TypeUtilisateur.findAll"));
    }

    /** Permet de récupérer une civilite par son nom
     * 
     * @return civilité
     */
    @WebMethod(operationName = "getCiviliteParNom")
    public CiviliteDto getCiviliteParNom(
            @WebParam(name = "civilite")final String civilite) 
            {
        Map<String, String> args = new HashMap<>();
        args.put("civilite", civilite);
        return CiviliteAssembleur
                .creationListeCiviliteDto(iDaoCivilite
                .rechercherParNamedQueryEtArguments(
                "Civilite.findByNom", args))
                .get(0);
    }

    /** Permet de récupérer un type d'utilisateur par son nom
     * 
     * @return type d'utilisateur
     */
    @WebMethod(operationName = "getTypeUtilisateurParNom")
    public TypeUtilisateurDto getTypeUtilisateurParNom(
            @WebParam(name = "typeUtilisateur")
            final String typeUtilisateur) {
        Map<String, String> args = new HashMap<>();
        args.put("typeUtilisateur", typeUtilisateur);
        return TypeUtilisateurAssembleur
                .creationListeTypeUtilisateurDto(iDaoTypeUtilisateur
                .rechercherParNamedQueryEtArguments(
                "TypeUtilisateur.findByNom", args))
                .get(0);
    }

    /** Permet d'ajouter une adresse en base de données
     * et de la lier à un utilisateur
     * @param adresse adresse a enregistrer
     * @param utilisateur identifiant de l'utilisateur
     * @return adresse enregistrer
     */
    @WebMethod(operationName = "enregistrerAdresse")
    public AdresseDto enregistrerAdresse(
            @WebParam(name = "adresseDto")final AdresseDto adresseDto
            , @WebParam(name = "utilisateur")
            final int utilisateur){
        // Ajout de la nouvelle adresse en base de données
        Adresse adresse = iDaoAdresse.ajouter(
                AdresseAssembleur.updateAdresse(adresseDto));
        
        if (adresse.getIdAdresse()!=null){
            iDaoUtilisateur.AjouterAdresse(utilisateur, adresse.getIdAdresse());
        }
        return AdresseAssembleur.creationAdresseDto(adresse);
    }

    /** Permet de crypter le mot de passe
     * @param mdp mode de passe a crypter
     * @return mot de passe crypter
     */
    private String cryptageMotDePasee(final String mdp) {
        byte[] key = mdp.getBytes();
        byte[] sha = null;

        try {
            sha = MessageDigest.getInstance("SHA").digest(key);
        } catch (NoSuchAlgorithmException ex) {
            Logger.getLogger(WsComptes.class.getName()).log(Level.SEVERE, null, ex);
        }
        StringBuilder hashString = new StringBuilder();
        for (int i = 0; i < sha.length; i++) {
            String hex = Integer.toHexString(sha[i]);
            if (hex.length() == 1) {
                hashString.append('0');
                hashString.append(hex.charAt(hex.length() - 1));
            } else {
                hashString.append(hex.substring(hex.length() - 2));
            }
        }
        return hashString.toString();
    }
}
